package middleware

import (
	"errors"
	"fmt"
	"net/http"
	"strconv"
	"strings"
	"time"
	permis "tupu-go/pkg/permission"
	"tupu-go/pkg/res"

	"github.com/gin-gonic/gin"
	"tupu-go/model"
)

// 非任务路径（如/api/v1/node/）：仅用户权限有效（第三方 Key 不涉及非任务资源，避免越权）。
// 任务路径（如/api/v1/tasks/123/）：用户权限和 Key 权限取 “或” 逻辑 —— 只要其中一种认证有权限，就允许访问。

// AuthMiddleware 权限校验中间件（合并用户Token和Key权限）
func AuthMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		// 1. 提取并校验两种认证信息（获取各自权限）
		userPerm, userErr := extractAndVerifyUser(c)     // 用户权限（可能为nil）
		keyPerm, keyErr := extractAndVerifyThirdParty(c) // Key权限（可能为nil）

		// 2. 基础校验：至少一种认证有效
		if userPerm == nil && keyPerm == nil {
			errMsg := "认证失败："
			if userErr != nil {
				errMsg += fmt.Sprintf("用户Token错误：%v；", userErr)
			}
			if keyErr != nil {
				errMsg += fmt.Sprintf("第三方Key错误：%v", keyErr)
			}
			//c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": errMsg})
			res.ErrorResponse(c, http.StatusUnauthorized, errors.New(errMsg))
			return
		}

		// 3. 合并权限校验（核心逻辑）
		if !checkMergedPermission(c.Request.URL.Path, c.Request.Method, userPerm, keyPerm) {
			res.ErrorResponse(c, http.StatusForbidden, errors.New("权限不足"))
			return
		}

		// 4. 上下文存储（记录权限来源）
		setAuthContext(c, userPerm, keyPerm)

		c.Next()
	}
}

// 提取并验证用户Token，返回用户权限（忽略无效Token，返回nil）
func extractAndVerifyUser(c *gin.Context) (*model.Permission, error) {
	authHeader := c.GetHeader("Token")
	if authHeader == "" {
		return nil, nil // 无用户Token，非错误
	}
	//parts := strings.Split(authHeader, " ")
	//if len(parts) != 2 || parts[0] != "Bearer" {
	//	return nil, errors.New("用户Token格式错误（应为Bearer <token>）")
	//}

	// 解析并校验Token
	userID, err := permis.ParseUserToken(authHeader)
	if err != nil {
		return nil, fmt.Errorf("用户Token无效：%v", err)
	}
	perm, err := permis.GetUserPermission(userID)
	if err != nil {
		return nil, fmt.Errorf("用户权限获取失败：%v", err)
	}

	// 校验半超管有效期
	if perm.PermissionType == "temp_admin" {
		now := time.Now()
		if perm.EffectiveTime != nil && now.Before(*perm.EffectiveTime) {
			return nil, errors.New("临时权限尚未生效")
		}
		if perm.ExpireTime != nil && now.After(*perm.ExpireTime) {
			return nil, errors.New("临时权限已过期")
		}
	}

	return perm, nil
}

// 提取并验证第三方Key，返回Key权限（忽略无效Key，返回nil）
func extractAndVerifyThirdParty(c *gin.Context) (*model.KeyPermission, error) {
	keyHeader := c.GetHeader("X-Key")
	if keyHeader == "" {
		return nil, nil // 无第三方Key，非错误
	}
	//parts := strings.Split(keyHeader, " ")
	//if len(parts) != 2 || parts[0] != "Key" {
	//	return nil, errors.New("第三方Key格式错误（应为Key <key>）")
	//}

	// 解析并校验Key
	keyID, taskID, err := permis.ParseThirdPartyKey(keyHeader)
	if err != nil {
		return nil, fmt.Errorf("第三方Key无效：%v", err)
	}
	perm, err := permis.GetKeyPermission(keyID)
	if err != nil {
		return nil, fmt.Errorf("Key权限获取失败：%v", err)
	}

	// 校验Key状态和任务匹配
	if !perm.Status {
		return nil, errors.New("第三方Key已禁用")
	}
	if perm.TaskID != taskID {
		return nil, errors.New("Key与任务不匹配")
	}

	return perm, nil
}

// 合并权限校验（用户权限 + Key权限，取"或"逻辑）
func checkMergedPermission(path, method string, userPerm *model.Permission, keyPerm *model.KeyPermission) bool {
	// 1. 非任务路径（如节点管理）：仅用户权限有效（Key不涉及非任务资源）
	if !strings.HasPrefix(path, "/api/v1/tasks/") {
		return checkUserPermission(path, method, userPerm)
	}

	// 2. 任务路径：用户权限或Key权限任意一个有效即可
	userHasPerm := checkUserPermission(path, method, userPerm)
	keyHasPerm := checkThirdPartyPermission(path, method, keyPerm)
	return userHasPerm || keyHasPerm
}

// 检查用户对路径的权限（单独校验用户）
func checkUserPermission(path, method string, userPerm *model.Permission) bool {
	if userPerm == nil {
		return false // 无用户权限
	}
	// 超管拥有所有权限
	if userPerm.PermissionType == "super" {
		return true
	}
	// 任务相关路径
	if strings.HasPrefix(path, "/api/v1/tasks/") {
		taskID := extractTaskIDFromPath(path)
		switch userPerm.PermissionType {
		case "admin": // 伪超管：仅查看
			return method == http.MethodGet
		case "normal", "temp_admin": // 普通/半超管：自己的任务可操作
			if method == http.MethodGet {
				return true
			}
			return permis.IsTaskOwner(strconv.FormatInt(userPerm.EmployeeID, 10), taskID)
		}
	}
	// 节点管理路径（仅超管/伪超管）
	if strings.HasPrefix(path, "/api/v1/node/") {
		return userPerm.PermissionType == "super" || userPerm.PermissionType == "admin"
	}
	return false
}

// 检查第三方Key对路径的权限（单独校验Key）
func checkThirdPartyPermission(path, method string, keyPerm *model.KeyPermission) bool {
	if keyPerm == nil {
		return false // 无Key权限
	}
	// 提取任务ID并校验
	taskID := extractTaskIDFromPath(path)
	if taskID == "" || taskID != keyPerm.TaskID {
		return false
	}
	// 校验Key的权限范围
	switch keyPerm.PermissionScope {
	case "read":
		return method == http.MethodGet
	case "write":
		return method == http.MethodGet || method == http.MethodPost || method == http.MethodPut
	case "operate":
		return method != http.MethodDelete
	default:
		return false
	}
}

// 提取任务ID
func extractTaskIDFromPath(path string) string {
	if strings.HasPrefix(path, "/api/v1/tasks/") {
		path = strings.TrimPrefix(path, "/api/v1/tasks/")
		if parts := strings.SplitN(path, "/", 2); len(parts) > 0 {
			return parts[0]
		}
	}
	return ""
}

// 设置上下文信息（记录权限来源）
func setAuthContext(c *gin.Context, userPerm *model.Permission, keyPerm *model.KeyPermission) {
	// 记录用户信息（若有）
	if userPerm != nil {
		c.Set("user_id", strconv.FormatInt(userPerm.EmployeeID, 10))
		c.Set("user_perm_type", userPerm.PermissionType)
	}
	// 记录Key信息（若有）
	if keyPerm != nil {
		c.Set("third_party_name", keyPerm.ThirdPartyName)
		c.Set("key_task_id", keyPerm.TaskID)
		c.Set("key_scope", keyPerm.PermissionScope)
	}
	// 记录权限来源（方便后续业务判断）
	if userPerm != nil && checkUserPermission(c.Request.URL.Path, c.Request.Method, userPerm) {
		c.Set("perm_source", "user")
	} else if keyPerm != nil && checkThirdPartyPermission(c.Request.URL.Path, c.Request.Method, keyPerm) {
		c.Set("perm_source", "key")
	}
}
